summaryrefslogtreecommitdiffstats
path: root/src/common/steady_clock.cpp
blob: 0d5908aa794e0ebb1bd7e9dfd57582ddf2c25980 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#if defined(_WIN32)
#include <windows.h>
#else
#include <time.h>
#endif

#include "common/steady_clock.h"

namespace Common {

#ifdef _WIN32
static s64 WindowsQueryPerformanceFrequency() {
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);
    return frequency.QuadPart;
}

static s64 WindowsQueryPerformanceCounter() {
    LARGE_INTEGER counter;
    QueryPerformanceCounter(&counter);
    return counter.QuadPart;
}
#endif

SteadyClock::time_point SteadyClock::Now() noexcept {
#if defined(_WIN32)
    static const auto freq = WindowsQueryPerformanceFrequency();
    const auto counter = WindowsQueryPerformanceCounter();

    // 10 MHz is a very common QPC frequency on modern PCs.
    // Optimizing for this specific frequency can double the performance of
    // this function by avoiding the expensive frequency conversion path.
    static constexpr s64 TenMHz = 10'000'000;

    if (freq == TenMHz) [[likely]] {
        static_assert(period::den % TenMHz == 0);
        static constexpr s64 Multiplier = period::den / TenMHz;
        return time_point{duration{counter * Multiplier}};
    }

    const auto whole = (counter / freq) * period::den;
    const auto part = (counter % freq) * period::den / freq;
    return time_point{duration{whole + part}};
#elif defined(__APPLE__)
    return time_point{duration{clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)}};
#else
    timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}};
#endif
}

}; // namespace Common